home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 12 / Example 12.8 / particles.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-06-30  |  8.3 KB  |  286 lines

  1. #include "particles.h"
  2.  
  3. DWORD FtoDword(float f){return *((DWORD*)&f);}
  4.  
  5. //Global Particle Textures
  6. IDirect3DTexture9* starTexture = NULL;
  7. IDirect3DTexture9* smokeTexture = NULL;
  8.  
  9. struct PARTICLE_VERTEX
  10. {
  11.     D3DXVECTOR3 position;
  12.     D3DCOLOR color;
  13.     static const DWORD FVF;
  14. };
  15.  
  16. const DWORD PARTICLE_VERTEX::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
  17.  
  18. int numParticles = 2048;
  19. IDirect3DVertexBuffer9* particleBuffer = NULL;
  20. DWORD bufferOffset = 0;
  21.  
  22. void LoadParticleResources(IDirect3DDevice9 *Dev)
  23. {
  24.     Dev->CreateVertexBuffer(numParticles * sizeof(PARTICLE_VERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY,
  25.                             PARTICLE_VERTEX::FVF, D3DPOOL_DEFAULT, &particleBuffer, NULL);
  26.  
  27.     //Load textures
  28.     D3DXCreateTextureFromFile(Dev, "textures/star.dds", &starTexture);
  29.     D3DXCreateTextureFromFile(Dev, "textures/smoke.dds", &smokeTexture);
  30. }
  31.  
  32. void UnloadParticleResources()
  33. {
  34.     if(particleBuffer)
  35.         particleBuffer->Release();
  36.     particleBuffer = NULL;
  37.  
  38.     //Release textures
  39.     if(starTexture)starTexture->Release();
  40.     if(smokeTexture)smokeTexture->Release();
  41.  
  42.     starTexture = NULL;
  43.     smokeTexture = NULL;
  44. }
  45.  
  46. //////////////////////////////////////////////////////////////////////////////////////////////
  47. //                                PARTICLE_SYSTEM                                                //
  48. //////////////////////////////////////////////////////////////////////////////////////////////
  49.  
  50. PARTICLE_SYSTEM::PARTICLE_SYSTEM(IDirect3DDevice9 *Dev) : EFFECT(Dev)
  51. {
  52.     m_pTexture = NULL;
  53.     m_blendMode = D3DBLEND_ONE;
  54.     m_particleSize = 3.0f;
  55. }
  56.  
  57. PARTICLE_SYSTEM::~PARTICLE_SYSTEM()
  58. {
  59.     //Delete all m_particles
  60.     for(int i=0;i<m_particles.size();i++)
  61.         delete m_particles[i];
  62.     m_particles.clear();
  63. }
  64.  
  65. void PARTICLE_SYSTEM::Update(float timeDelta)
  66. {
  67.     
  68. }
  69.  
  70. void PARTICLE_SYSTEM::Render()
  71. {
  72.     if(m_particles.empty() || particleBuffer == NULL)return;
  73.  
  74.     PreRender();
  75.  
  76.     m_pDevice->SetTexture(0, m_pTexture);
  77.     m_pDevice->SetFVF(PARTICLE_VERTEX::FVF);
  78.     m_pDevice->SetStreamSource(0, particleBuffer, 0, sizeof(PARTICLE_VERTEX));
  79.  
  80.     int batchSize = 512;
  81.  
  82.     for(int i=0;i<m_particles.size();i+=batchSize)
  83.         RenderBatch(i, batchSize);
  84.  
  85.     PostRender();
  86. }
  87.  
  88. void PARTICLE_SYSTEM::RenderBatch(int start, int batchSize)
  89. {
  90.     //If we will reach the end of the vertex buffer, start over
  91.     if(bufferOffset + batchSize >= numParticles)bufferOffset = 0;
  92.  
  93.     //Lock the vertex buffer
  94.     PARTICLE_VERTEX *p = NULL;
  95.     particleBuffer->Lock(bufferOffset * sizeof(PARTICLE_VERTEX), 
  96.                          batchSize, (void**)&p, 
  97.                          bufferOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
  98.  
  99.     int particlesRendered = 0;
  100.     for(int i=start;i<m_particles.size() && i < start + batchSize;i++)
  101.         if(!m_particles[i]->dead)
  102.         {
  103.             p->position = m_particles[i]->position;
  104.             p->color = m_particles[i]->color;
  105.             p++;
  106.             particlesRendered++;
  107.         }
  108.  
  109.     particleBuffer->Unlock();
  110.  
  111.     //Render batch 
  112.     if(particlesRendered > 0)
  113.         m_pDevice->DrawPrimitive(D3DPT_POINTLIST, bufferOffset, particlesRendered);
  114.  
  115.     //Increase offset
  116.     bufferOffset += batchSize;
  117. }
  118.  
  119. bool PARTICLE_SYSTEM::isDead()
  120. {
  121.     return true;
  122. }
  123.  
  124. void PARTICLE_SYSTEM::PreRender()
  125. {
  126.     m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
  127.     m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true);
  128.     m_pDevice->SetRenderState(D3DRS_POINTSIZE, FtoDword(m_particleSize));
  129.     m_pDevice->SetRenderState(D3DRS_POINTSCALE_A, FtoDword(0.0f));
  130.     m_pDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDword(0.0f));
  131.     m_pDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDword(1.0f));
  132.     m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  133.  
  134.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  135.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
  136.     m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  137.     m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  138.     m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
  139.     m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  140.  
  141.     m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
  142.     m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  143.     m_pDevice->SetRenderState(D3DRS_DESTBLEND, m_blendMode);
  144.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, false);
  145. }
  146.  
  147. void PARTICLE_SYSTEM::PostRender()
  148. {
  149.     m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
  150.     m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  151.  
  152.     m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
  153.     m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, false);
  154. }
  155.  
  156. //////////////////////////////////////////////////////////////////////////////////////////////
  157. //                                MAGIC SHOWER                                                //
  158. //////////////////////////////////////////////////////////////////////////////////////////////
  159.  
  160. MAGIC_SHOWER::MAGIC_SHOWER(IDirect3DDevice9 *Dev, int noParticles, D3DXVECTOR3 _origin) : PARTICLE_SYSTEM(Dev)
  161. {
  162.     m_origin = _origin;
  163.  
  164.     //Add initial particles
  165.     for(int i=0;i<noParticles;i++)
  166.     {
  167.         PARTICLE *p = new PARTICLE();
  168.         memset(p, 0, sizeof(PARTICLE));
  169.         p->time_to_live = rand()%5000 / 1000.0f;
  170.         p->color.a = 0.0f;
  171.         p->acceleration = D3DXVECTOR3(0.0f, -0.5f, 0.0f);
  172.         m_particles.push_back(p);
  173.     }
  174.  
  175.     m_pTexture = starTexture;
  176. }
  177.  
  178. void MAGIC_SHOWER::Update(float timeDelta)
  179. {
  180.     for(int i=0;i<m_particles.size();i++)
  181.     {
  182.         m_particles[i]->time_to_live -= timeDelta;
  183.         m_particles[i]->velocity += m_particles[i]->acceleration * timeDelta;    //Gravity
  184.         m_particles[i]->position += m_particles[i]->velocity * timeDelta;
  185.         m_particles[i]->color.a = m_particles[i]->time_to_live / 5.0f;
  186.  
  187.         if(m_particles[i]->time_to_live <= 0.0f)    //Re-spawn
  188.         {
  189.             m_particles[i]->position = m_origin;
  190.             
  191.             m_particles[i]->velocity = D3DXVECTOR3((rand()%2000 / 1000.0f) - 1.0f,
  192.                                                  (rand()%2000 / 1000.0f) - 1.0f,
  193.                                                  (rand()%2000 / 1000.0f) - 1.0f);
  194.  
  195.             D3DXVec3Normalize(&m_particles[i]->velocity, &m_particles[i]->velocity);
  196.             m_particles[i]->velocity *= 2.0f;
  197.  
  198.             m_particles[i]->color = D3DXCOLOR(rand()%1000 / 1000.0f, rand()%1000 / 1000.0f, rand()%1000 / 1000.0f, 1.0f);
  199.  
  200.             m_particles[i]->time_to_live = rand()%4000 / 1000.0f + 1.0f;
  201.         }
  202.     }
  203. }
  204.  
  205. bool MAGIC_SHOWER::isDead()
  206. {
  207.     return false;
  208. }
  209.  
  210. //////////////////////////////////////////////////////////////////////////////////////////////
  211. //                                SMOKE                                                        //
  212. //////////////////////////////////////////////////////////////////////////////////////////////
  213.  
  214. SMOKE::SMOKE(IDirect3DDevice9 *Dev, int noParticles, D3DXVECTOR3 _origin) : PARTICLE_SYSTEM(Dev)
  215. {
  216.     m_origin = _origin;
  217.  
  218.     //Add initial particles
  219.     for(int i=0;i<noParticles;i++)
  220.     {
  221.         PARTICLE *p = new PARTICLE();
  222.         memset(p, 0, sizeof(PARTICLE));
  223.         p->time_to_live = rand()%5000 / 1000.0f;
  224.         p->dead = true;
  225.         p->acceleration = D3DXVECTOR3(-0.2f, 0.5f, 0.2f);        //Sideways wind
  226.         m_particles.push_back(p);
  227.     }
  228.  
  229.     m_blendMode = D3DBLEND_INVSRCALPHA;
  230.     m_particleSize = 15.0f;
  231.     m_pTexture = smokeTexture;
  232. }
  233.  
  234. void SMOKE::Update(float timeDelta)
  235. {
  236.     for(int i=0;i<m_particles.size();i++)
  237.     {
  238.         m_particles[i]->time_to_live -= timeDelta;
  239.         m_particles[i]->velocity += m_particles[i]->acceleration * timeDelta;    //Wind
  240.         m_particles[i]->position += m_particles[i]->velocity * timeDelta;
  241.  
  242.         float aim = m_particles[i]->time_to_live / 10.0f;
  243.  
  244.         if(m_particles[i]->time_to_live <= 0.0f)    //Re-spawn
  245.             m_particles[i]->color.a -= timeDelta * 0.05f;
  246.         else if(m_particles[i]->color.a < aim)
  247.             m_particles[i]->color.a += timeDelta * 0.015f;
  248.  
  249.         if(m_particles[i]->color.a < 0.0f)
  250.         {
  251.             //Random start position
  252.             D3DXVECTOR3 p = D3DXVECTOR3((rand()%2000 / 1000.0f) - 1.0f,
  253.                                         (rand()%2000 / 1000.0f) - 1.0f,
  254.                                         (rand()%2000 / 1000.0f) - 1.0f);
  255.             p *= 3.0f;
  256.             p.y -= (rand()%2000) / 1000.0f;
  257.             if(rand()%15 == 0)p.y -= 15.0f;
  258.  
  259.             m_particles[i]->position = m_origin + p;        
  260.  
  261.             //Circular direction
  262.             float angle = (rand()%6280) / 1000.0f;
  263.             float spread = ((rand()%1000) / 1000.0f) * 2.0f;
  264.  
  265.             m_particles[i]->velocity = D3DXVECTOR3(cos(angle) * spread,
  266.                                                  1.0f + ((rand()%2000 / 1000.0f) - 1.0f) * 0.5f,
  267.                                                  sin(angle) * spread);
  268.  
  269.             D3DXVec3Normalize(&m_particles[i]->velocity, &m_particles[i]->velocity);
  270.             m_particles[i]->velocity *= 2.0f;
  271.  
  272.             //Random graydscale color
  273.             float m_c = rand()%900 / 1000.0f + 0.1f;
  274.             m_particles[i]->color = D3DXCOLOR(m_c, m_c, m_c, 0.01f);
  275.  
  276.             m_particles[i]->time_to_live = rand()%6000 / 1000.0f + 1.0f;
  277.  
  278.             m_particles[i]->dead = false;
  279.         }
  280.     }
  281. }
  282.  
  283. bool SMOKE::isDead()
  284. {
  285.     return false;
  286. }